package grade.calculate.read;

import grade.calculate.config.Configure;
import grade.calculate.listener.Listener;
import grade.calculate.listener.ReadListener;
import grade.calculate.pojo.Data;
import grade.calculate.pojo.Student;
import lombok.NoArgsConstructor;

import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Optional;

/**
 * 学业表现分读取模版方法 自定义读取方法必须继承此方法
 * <p>
 * 注意继承后还必须写传入参数为Data的构造方法并在构造方法内通过super(data)
 * 获取到启动时配置的参数和其它事件处理结果数据
 * </p>
 *
 * @author fromdrowning
 * @date 2024/2/22 5:47
 */
@NoArgsConstructor
public abstract class AbstractRead {

    /**
     * 需要读取的Excel文件路径
     */
    protected String inputFilePath;

    /**
     * 需要读取Excel的文件名 文件要放在resources下并带上文件后缀
     */
    protected String inputFileName;

    /**
     * 读取Excel文件的表 默认第一张表
     */
    protected Integer sheetNum;

    /**
     * 事件监听器 默认初始化了一个{@link ReadListener}监听器
     */
    protected Listener listener;

    /**
     * 封装{@link Configure}启动时配置的参数和其它事件处理结果数据
     */
    protected Data data;

    /**
     * 从Excel中读的学生信息集合
     */
    protected List<Student> studentList;

    /**
     * 本学期所有需要计算学业表现的课程
     */
    protected List<String> semesterCourseList;

    /**
     * 带参构造方法
     * <p>
     * 注意继承后还必须写传入参数为Data的构造方法并在构造方法内通过super(data)
     * 调用此构造方法获取到启动时配置的参数和其它事件处理结果数据
     * </p>
     *
     * @param data {@link Data}用于各个事件之间获取数据
     */
    protected AbstractRead(Data data) {
        String resourcePath = getResourcePath();
        this.inputFileName = data.getInputFileName();
        this.inputFilePath = resourcePath + inputFileName;
        this.sheetNum = data.getSheetNum();
        this.semesterCourseList = data.getSemesterCourseList();
        this.studentList = data.getStudentList();
        this.listener = data.getListener();
        this.data = data;
    }

    /**
     * 获取resources文件路径
     *
     * @return {@link String} resources文件路径
     */
    private String getResourcePath() {
        // 获取路径前需要判断resources文件是否存在
        URL resource = Optional.ofNullable(this.getClass().getClassLoader().getResource(""))
                .orElseThrow(() -> new RuntimeException("找不到resources文件"));

        return resource.getPath();
    }

    /**
     * 学业表现分读取入口方法
     * <p>执行完read方法后会调用监听器 按照添加事件的顺序 运行事件的run方法</p>
     *
     * @throws IOException 找不到读取的文件时抛出此异常
     */
    public void run() throws IOException {
        long start = System.currentTimeMillis();

        read();

        long end = System.currentTimeMillis();
        System.out.println("读取成功 共耗时" + (end - start) / 1000.0 + "秒");

        // 调用监听器 按照添加事件的顺序 运行事件的run方法
        listener.notifyAllEvent(data);
    }

    /**
     * 学业表现分读取抽象方法
     *
     * @throws IOException 找不到读取的文件时抛出此异常
     */
    protected abstract void read() throws IOException;
}
